home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65 / src / recipient.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-05  |  13.1 KB  |  580 lines

  1. /*
  2.  * Copyright (c) 1983 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted provided
  7.  * that: (1) source distributions retain this entire copyright notice and
  8.  * comment, and (2) distributions including binaries display the following
  9.  * acknowledgement:  ``This product includes software developed by the
  10.  * University of California, Berkeley and its contributors'' in the
  11.  * documentation or other materials provided with the distribution and in
  12.  * all advertising materials mentioning features or use of this software.
  13.  * Neither the name of the University nor the names of its contributors may
  14.  * be used to endorse or promote products derived from this software without
  15.  * specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  17.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  18.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #ifndef lint
  22. static char sccsid[] = "@(#)recipient.c    5.18 (Berkeley) 6/1/90";
  23. #endif /* not lint */
  24.  
  25. # include <sys/types.h>
  26. # include <sys/stat.h>
  27. # include <pwd.h>
  28. # include "sendmail.h"
  29.  
  30. /*
  31. **  SENDTOLIST -- Designate a send list.
  32. **
  33. **    The parameter is a comma-separated list of people to send to.
  34. **    This routine arranges to send to all of them.
  35. **
  36. **    Parameters:
  37. **        list -- the send list.
  38. **        ctladdr -- the address template for the person to
  39. **            send to -- effective uid/gid are important.
  40. **            This is typically the alias that caused this
  41. **            expansion.
  42. **        sendq -- a pointer to the head of a queue to put
  43. **            these people into.
  44. **
  45. **    Returns:
  46. **        none
  47. **
  48. **    Side Effects:
  49. **        none.
  50. */
  51.  
  52. # define MAXRCRSN    10
  53.  
  54. sendtolist(list, ctladdr, sendq)
  55.     char *list;
  56.     ADDRESS *ctladdr;
  57.     ADDRESS **sendq;
  58. {
  59.     register char *p;
  60.     register ADDRESS *al;    /* list of addresses to send to */
  61.     bool firstone;        /* set on first address sent */
  62.     bool selfref;        /* set if this list includes ctladdr */
  63.     char delimiter;        /* the address delimiter */
  64.  
  65.     if (tTd(25, 1))
  66.     {
  67.         printf("sendto: %s\n   ctladdr=", list);
  68.         printaddr(ctladdr, FALSE);
  69.     }
  70.  
  71.     /* heuristic to determine old versus new style addresses */
  72.     if (ctladdr == NULL &&
  73.         (index(list, ',') != NULL || index(list, ';') != NULL ||
  74.          index(list, '<') != NULL || index(list, '(') != NULL))
  75.         CurEnv->e_flags &= ~EF_OLDSTYLE;
  76.     delimiter = ' ';
  77.     if (!bitset(EF_OLDSTYLE, CurEnv->e_flags) || ctladdr != NULL)
  78.         delimiter = ',';
  79.  
  80.     firstone = TRUE;
  81.     selfref = FALSE;
  82.     al = NULL;
  83.  
  84.     for (p = list; *p != '\0'; )
  85.     {
  86.         register ADDRESS *a;
  87.         extern char *DelimChar;        /* defined in prescan */
  88.  
  89.         /* parse the address */
  90.         while (isspace(*p) || *p == ',')
  91.             p++;
  92.         a = parseaddr(p, (ADDRESS *) NULL, 1, delimiter);
  93.         p = DelimChar;
  94.         if (a == NULL)
  95.             continue;
  96.         a->q_next = al;
  97.         a->q_alias = ctladdr;
  98.  
  99.         /* see if this should be marked as a primary address */
  100.         if (ctladdr == NULL ||
  101.             (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags)))
  102.             a->q_flags |= QPRIMARY;
  103.  
  104.         /* put on send queue or suppress self-reference */
  105.         if (ctladdr != NULL && sameaddr(ctladdr, a))
  106.             selfref = TRUE;
  107.         else
  108.             al = a;
  109.         firstone = FALSE;
  110.     }
  111.  
  112.     /* if this alias doesn't include itself, delete ctladdr */
  113.     if (!selfref && ctladdr != NULL)
  114.         ctladdr->q_flags |= QDONTSEND;
  115.  
  116.     /* arrange to send to everyone on the local send list */
  117.     while (al != NULL)
  118.     {
  119.         register ADDRESS *a = al;
  120.         extern ADDRESS *recipient();
  121.  
  122.         al = a->q_next;
  123.         setctladdr(a);
  124.         a = recipient(a, sendq);
  125.  
  126.         /* arrange to inherit full name */
  127.         if (a->q_fullname == NULL && ctladdr != NULL)
  128.             a->q_fullname = ctladdr->q_fullname;
  129.     }
  130.  
  131.     CurEnv->e_to = NULL;
  132. }
  133. /*
  134. **  RECIPIENT -- Designate a message recipient
  135. **
  136. **    Saves the named person for future mailing.
  137. **
  138. **    Parameters:
  139. **        a -- the (preparsed) address header for the recipient.
  140. **        sendq -- a pointer to the head of a queue to put the
  141. **            recipient in.  Duplicate supression is done
  142. **            in this queue.
  143. **
  144. **    Returns:
  145. **        The actual address in the queue.  This will be "a" if
  146. **        the address is not a duplicate, else the original address.
  147. **
  148. **    Side Effects:
  149. **        none.
  150. */
  151.  
  152. ADDRESS *
  153. recipient(a, sendq)
  154.     register ADDRESS *a;
  155.     register ADDRESS **sendq;
  156. {
  157.     register ADDRESS *q;
  158.     ADDRESS **pq;
  159.     register struct mailer *m;
  160.     register char *p;
  161.     bool quoted = FALSE;        /* set if the addr has a quote bit */
  162.     char buf[MAXNAME];        /* unquoted image of the user name */
  163.     extern ADDRESS *getctladdr();
  164.     extern bool safefile();
  165.  
  166.     CurEnv->e_to = a->q_paddr;
  167.     m = a->q_mailer;
  168.     errno = 0;
  169.     if (tTd(26, 1))
  170.     {
  171.         printf("\nrecipient: ");
  172.         printaddr(a, FALSE);
  173.     }
  174.  
  175.     /* break aliasing loops */
  176.     if (AliasLevel > MAXRCRSN)
  177.     {
  178.         usrerr("aliasing/forwarding loop broken");
  179.         return (a);
  180.     }
  181.  
  182.     /*
  183.     **  Finish setting up address structure.
  184.     */
  185.  
  186.     /* set the queue timeout */
  187.     a->q_timeout = TimeOut;
  188.  
  189.     /* map user & host to lower case if requested on non-aliases */
  190.     if (a->q_alias == NULL)
  191.         loweraddr(a);
  192.  
  193.     /* get unquoted user for file, program or user.name check */
  194.     (void) strcpy(buf, a->q_user);
  195.     for (p = buf; *p != '\0' && !quoted; p++)
  196.     {
  197.         if (!isascii(*p) && (*p & 0377) != (SpaceSub & 0377))
  198.             quoted = TRUE;
  199.     }
  200.     stripquotes(buf, TRUE);
  201.  
  202.     /* do sickly crude mapping for program mailing, etc. */
  203.     if (m == LocalMailer && buf[0] == '|')
  204.     {
  205.         a->q_mailer = m = ProgMailer;
  206.         a->q_user++;
  207.         if (a->q_alias == NULL && !QueueRun && !ForceMail)
  208.         {
  209.             a->q_flags |= QDONTSEND|QBADADDR;
  210.             usrerr("Cannot mail directly to programs");
  211.         }
  212.     }
  213.  
  214.     /*
  215.     **  Look up this person in the recipient list.
  216.     **    If they are there already, return, otherwise continue.
  217.     **    If the list is empty, just add it.  Notice the cute
  218.     **    hack to make from addresses suppress things correctly:
  219.     **    the QDONTSEND bit will be set in the send list.
  220.     **    [Please note: the emphasis is on "hack."]
  221.     */
  222.  
  223.     for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
  224.     {
  225.         if (!ForceMail && sameaddr(q, a))
  226.         {
  227.             if (tTd(26, 1))
  228.             {
  229.                 printf("%s in sendq: ", a->q_paddr);
  230.                 printaddr(q, FALSE);
  231.             }
  232.             if (!bitset(QDONTSEND, a->q_flags))
  233.                 message(Arpa_Info, "duplicate suppressed");
  234.             if (!bitset(QPRIMARY, q->q_flags))
  235.                 q->q_flags |= a->q_flags;
  236.             return (q);
  237.         }
  238.     }
  239.  
  240.     /* add address on list */
  241.     *pq = a;
  242.     a->q_next = NULL;
  243.     CurEnv->e_nrcpts++;
  244.  
  245.     /*
  246.     **  Alias the name and handle :include: specs.
  247.     */
  248.  
  249.     if (m == LocalMailer && !bitset(QDONTSEND, a->q_flags))
  250.     {
  251.         if (strncmp(a->q_user, ":include:", 9) == 0)
  252.         {
  253.             a->q_flags |= QDONTSEND;
  254.             if (a->q_alias == NULL && !QueueRun && !ForceMail)
  255.             {
  256.                 a->q_flags |= QBADADDR;
  257.                 usrerr("Cannot mail directly to :include:s");
  258.             }
  259.             else
  260.             {
  261.                 message(Arpa_Info, "including file %s", &a->q_user[9]);
  262.                 include(&a->q_user[9], " sending", a, sendq);
  263.             }
  264.         }
  265.         else
  266.             alias(a, sendq);
  267.     }
  268.  
  269.     /*
  270.     **  If the user is local and still being sent, verify that
  271.     **  the address is good.  If it is, try to forward.
  272.     **  If the address is already good, we have a forwarding
  273.     **  loop.  This can be broken by just sending directly to
  274.     **  the user (which is probably correct anyway).
  275.     */
  276.  
  277.     if (!bitset(QDONTSEND, a->q_flags) && m == LocalMailer)
  278.     {
  279.         struct stat stb;
  280.         extern bool writable();
  281.  
  282.         /* see if this is to a file */
  283.         if (buf[0] == '/')
  284.         {
  285.             p = rindex(buf, '/');
  286.             /* check if writable or creatable */
  287.             if (a->q_alias == NULL && !QueueRun && !ForceMail)
  288.             {
  289.                 a->q_flags |= QDONTSEND|QBADADDR;
  290.                 usrerr("Cannot mail directly to files");
  291.             }
  292.             else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) :
  293.                 (*p = '\0', !safefile(buf, getruid(), S_IWRITE|S_IEXEC)))
  294.             {
  295.                 a->q_flags |= QBADADDR;
  296.                 giveresponse(EX_CANTCREAT, m, CurEnv);
  297.             }
  298.         }
  299.         else
  300.         {
  301.             register struct passwd *pw;
  302.             extern struct passwd *finduser();
  303.  
  304.             /* warning -- finduser may trash buf */
  305.             pw = finduser(buf);
  306.             if (pw == NULL)
  307.             {
  308.                 a->q_flags |= QBADADDR;
  309.                 giveresponse(EX_NOUSER, m, CurEnv);
  310.             }
  311.             else
  312.             {
  313.                 char nbuf[MAXNAME];
  314.  
  315.                 if (strcmp(a->q_user, pw->pw_name) != 0)
  316.                 {
  317.                     a->q_user = newstr(pw->pw_name);
  318.                     (void) strcpy(buf, pw->pw_name);
  319.                 }
  320.                 a->q_home = newstr(pw->pw_dir);
  321.                 a->q_uid = pw->pw_uid;
  322.                 a->q_gid = pw->pw_gid;
  323.                 a->q_flags |= QGOODUID;
  324.                 buildfname(pw->pw_gecos, pw->pw_name, nbuf);
  325.                 if (nbuf[0] != '\0')
  326.                     a->q_fullname = newstr(nbuf);
  327.                 if (!quoted)
  328.                     forward(a, sendq);
  329.             }
  330.         }
  331.     }
  332.     return (a);
  333. }
  334. /*
  335. **  FINDUSER -- find the password entry for a user.
  336. **
  337. **    This looks a lot like getpwnam, except that it may want to
  338. **    do some fancier pattern matching in /etc/passwd.
  339. **
  340. **    This routine contains most of the time of many sendmail runs.
  341. **    It deserves to be optimized.
  342. **
  343. **    Parameters:
  344. **        name -- the name to match against.
  345. **
  346. **    Returns:
  347. **        A pointer to a pw struct.
  348. **        NULL if name is unknown or ambiguous.
  349. **
  350. **    Side Effects:
  351. **        may modify name.
  352. */
  353.  
  354. struct passwd *
  355. finduser(name)
  356.     char *name;
  357. {
  358.     register struct passwd *pw;
  359.     register char *p;
  360.     extern struct passwd *getpwent();
  361.     extern struct passwd *getpwnam();
  362.  
  363.     /* map upper => lower case */
  364.     for (p = name; *p != '\0'; p++)
  365.     {
  366.         if (isascii(*p) && isupper(*p))
  367.             *p = tolower(*p);
  368.     }
  369.  
  370.     /* look up this login name using fast path */
  371.     if ((pw = getpwnam(name)) != NULL)
  372.         return (pw);
  373.  
  374.     /* search for a matching full name instead */
  375.     for (p = name; *p != '\0'; p++)
  376.     {
  377.         if (*p == (SpaceSub & 0177) || *p == '_')
  378.             *p = ' ';
  379.     }
  380.     (void) setpwent();
  381.     while ((pw = getpwent()) != NULL)
  382.     {
  383.         char buf[MAXNAME];
  384.  
  385.         buildfname(pw->pw_gecos, pw->pw_name, buf);
  386.         if (index(buf, ' ') != NULL && !strcasecmp(buf, name))
  387.         {
  388.             message(Arpa_Info, "sending to login name %s", pw->pw_name);
  389.             return (pw);
  390.         }
  391.     }
  392.     return (NULL);
  393. }
  394. /*
  395. **  WRITABLE -- predicate returning if the file is writable.
  396. **
  397. **    This routine must duplicate the algorithm in sys/fio.c.
  398. **    Unfortunately, we cannot use the access call since we
  399. **    won't necessarily be the real uid when we try to
  400. **    actually open the file.
  401. **
  402. **    Notice that ANY file with ANY execute bit is automatically
  403. **    not writable.  This is also enforced by mailfile.
  404. **
  405. **    Parameters:
  406. **        s -- pointer to a stat struct for the file.
  407. **
  408. **    Returns:
  409. **        TRUE -- if we will be able to write this file.
  410. **        FALSE -- if we cannot write this file.
  411. **
  412. **    Side Effects:
  413. **        none.
  414. */
  415.  
  416. bool
  417. writable(s)
  418.     register struct stat *s;
  419. {
  420.     int euid, egid;
  421.     int bits;
  422.  
  423.     if (bitset(0111, s->st_mode))
  424.         return (FALSE);
  425.     euid = getruid();
  426.     egid = getrgid();
  427.     if (geteuid() == 0)
  428.     {
  429.         if (bitset(S_ISUID, s->st_mode))
  430.             euid = s->st_uid;
  431.         if (bitset(S_ISGID, s->st_mode))
  432.             egid = s->st_gid;
  433.     }
  434.  
  435.     if (euid == 0)
  436.         return (TRUE);
  437.     bits = S_IWRITE;
  438.     if (euid != s->st_uid)
  439.     {
  440.         bits >>= 3;
  441.         if (egid != s->st_gid)
  442.             bits >>= 3;
  443.     }
  444.     return ((s->st_mode & bits) != 0);
  445. }
  446. /*
  447. **  INCLUDE -- handle :include: specification.
  448. **
  449. **    Parameters:
  450. **        fname -- filename to include.
  451. **        msg -- message to print in verbose mode.
  452. **        ctladdr -- address template to use to fill in these
  453. **            addresses -- effective user/group id are
  454. **            the important things.
  455. **        sendq -- a pointer to the head of the send queue
  456. **            to put these addresses in.
  457. **
  458. **    Returns:
  459. **        none.
  460. **
  461. **    Side Effects:
  462. **        reads the :include: file and sends to everyone
  463. **        listed in that file.
  464. */
  465.  
  466. include(fname, msg, ctladdr, sendq)
  467.     char *fname;
  468.     char *msg;
  469.     ADDRESS *ctladdr;
  470.     ADDRESS **sendq;
  471. {
  472.     char buf[MAXLINE];
  473.     register FILE *fp;
  474.     char *oldto = CurEnv->e_to;
  475.     char *oldfilename = FileName;
  476.     int oldlinenumber = LineNumber;
  477.  
  478.     fp = fopen(fname, "r");
  479.     if (fp == NULL)
  480.     {
  481.         usrerr("Cannot open %s", fname);
  482.         return;
  483.     }
  484.     if (getctladdr(ctladdr) == NULL)
  485.     {
  486.         struct stat st;
  487.  
  488.         if (fstat(fileno(fp), &st) < 0)
  489.             syserr("Cannot fstat %s!", fname);
  490.         ctladdr->q_uid = st.st_uid;
  491.         ctladdr->q_gid = st.st_gid;
  492.         ctladdr->q_flags |= QGOODUID;
  493.     }
  494.  
  495.     /* read the file -- each line is a comma-separated list. */
  496.     FileName = fname;
  497.     LineNumber = 0;
  498.     while (fgets(buf, sizeof buf, fp) != NULL)
  499.     {
  500.         register char *p = index(buf, '\n');
  501.  
  502.         LineNumber++;
  503.         if (p != NULL)
  504.             *p = '\0';
  505.         if (buf[0] == '\0')
  506.             continue;
  507.         CurEnv->e_to = oldto;
  508.         message(Arpa_Info, "%s to %s", msg, buf);
  509.         AliasLevel++;
  510.         sendtolist(buf, ctladdr, sendq);
  511.         AliasLevel--;
  512.     }
  513.  
  514.     (void) fclose(fp);
  515.     FileName = oldfilename;
  516.     LineNumber = oldlinenumber;
  517. }
  518. /*
  519. **  SENDTOARGV -- send to an argument vector.
  520. **
  521. **    Parameters:
  522. **        argv -- argument vector to send to.
  523. **
  524. **    Returns:
  525. **        none.
  526. **
  527. **    Side Effects:
  528. **        puts all addresses on the argument vector onto the
  529. **            send queue.
  530. */
  531.  
  532. sendtoargv(argv)
  533.     register char **argv;
  534. {
  535.     register char *p;
  536.  
  537.     while ((p = *argv++) != NULL)
  538.     {
  539.         if (argv[0] != NULL && argv[1] != NULL && !strcasecmp(argv[0], "at"))
  540.         {
  541.             char nbuf[MAXNAME];
  542.  
  543.             if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf)
  544.                 usrerr("address overflow");
  545.             else
  546.             {
  547.                 (void) strcpy(nbuf, p);
  548.                 (void) strcat(nbuf, "@");
  549.                 (void) strcat(nbuf, argv[1]);
  550.                 p = newstr(nbuf);
  551.                 argv += 2;
  552.             }
  553.         }
  554.         sendtolist(p, (ADDRESS *) NULL, &CurEnv->e_sendqueue);
  555.     }
  556. }
  557. /*
  558. **  GETCTLADDR -- get controlling address from an address header.
  559. **
  560. **    If none, get one corresponding to the effective userid.
  561. **
  562. **    Parameters:
  563. **        a -- the address to find the controller of.
  564. **
  565. **    Returns:
  566. **        the controlling address.
  567. **
  568. **    Side Effects:
  569. **        none.
  570. */
  571.  
  572. ADDRESS *
  573. getctladdr(a)
  574.     register ADDRESS *a;
  575. {
  576.     while (a != NULL && !bitset(QGOODUID, a->q_flags))
  577.         a = a->q_alias;
  578.     return (a);
  579. }
  580.